package com.spring.ioc.study.context;

import com.spring.ioc.study.annotation.Autowired;
import com.spring.ioc.study.annotation.Component;
import com.spring.ioc.study.annotation.Qualifier;
import com.spring.ioc.study.annotation.Value;
import com.spring.ioc.study.util.ClassUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @Description: 注解context自己实现
 * @Author: 梁飞
 * @Date: 2021-08-24 10:40
 */
public class MyAnnotationConfigApplicationContext {

    private static final ConcurrentMap<String, Object> beanDefinitionMap = new ConcurrentHashMap();


    public MyAnnotationConfigApplicationContext(String pack) {
        // 传入包路径获取bean
        Set<BeanDefinition> beanDefinitions = this.getBeanDefinitions(pack);
        this.createObject(beanDefinitions);
        this.autoWiredObject(beanDefinitions);

    }

    //自动装载
    private void autoWiredObject(Set<BeanDefinition> beanDefinitions) {
        for (BeanDefinition beanDefinition : beanDefinitions) {
            Class beanClass = beanDefinition.getBeanClass();
            Field[] declaredFields = beanClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                Autowired autowired = declaredField.getAnnotation(Autowired.class);
                if (autowired != null) {
                    String value;
                    Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);
                    if (qualifier != null&&qualifier.value()!="") {
                        // byName
                        value = qualifier.value();
                    }else{
                        // byType
                        value = ClassUtil.toLowerCaseFirstOne(declaredField.getName());
                    }
                    Object bean = this.getBean(value);
                    Object bean1 = this.getBean(beanDefinition.getBeanName());
                    declaredField.setAccessible(true);
                    try {
                        declaredField.set(bean1,bean);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public Object getBean(String beanName){
        return beanDefinitionMap.get(beanName);
    }

    public void createObject(Set<BeanDefinition> beanDefinitions) {
        for (BeanDefinition beanDefinition : beanDefinitions) {
            Class beanClass = beanDefinition.getBeanClass();
            try {
                // 根据无参构造创建对象
                Object object = beanClass.getConstructor().newInstance();
                // 赋值
                // getFields()：获得某个类的所有的公共（public）的字段，包括父类中的字段。
                // getDeclaredFields()：获得某个类的所有声明的字段，即包括public、private和proteced，但是不包括父类的申明字段。
                Field[] fields = beanClass.getDeclaredFields();
                for (Field field : fields) {
                    Value valueAnnotation = field.getDeclaredAnnotation(Value.class);
                    if (valueAnnotation != null) {
                        String value1 = valueAnnotation.value();
                        field.setAccessible(true);
                        Object value2=null;
                        switch (field.getType().getSimpleName()){
                            case "Integer":
                                value2=Integer.parseInt(value1);
                                break;
                            case "String":
                                value2=value1;
                                break;
                            case "Float":
                                value2=Float.parseFloat(value1);
                                break;
                            default:
                                break;
                        }
                        field.set(object,value2);
                    }
                }
                String beanName = beanDefinition.getBeanName();
                beanDefinitionMap.put(beanName, object);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    public Set<BeanDefinition> getBeanDefinitions(String pack) {
        Set<BeanDefinition> beanDefinitions = new HashSet<>();
        //1.获取到包下的所有类
        List<Class<?>> classes = ClassUtil.getClasses(pack);
        //2.遍历这些类
        Iterator<Class<?>> iterator = classes.iterator();
        while (iterator.hasNext()) {
            Class<?> clazz = iterator.next();
            //2.1 找到有相应注解的类
            Component annotation = clazz.getAnnotation(Component.class);
            if (annotation != null) {
                String value = annotation.value();
                //2.2 如果注解beanName没有命名,则获取类名并且把类名的第一个字母转为小写,作为beanName.
                if ("".equals(value)) {
                    // 方式-1
                    // String name = clazz.getName();
                    // String packName = clazz.getPackage().getName();
                    // value = ClassUtil.toLowerCaseFirstOne(name.replace(packName+".",""));
                    // 方式-2
                    value = ClassUtil.toLowerCaseFirstOne(clazz.getSimpleName());
                }
                //3.把bean放入beanDefinition中
                beanDefinitions.add(new BeanDefinition(value, clazz));
            }
        }
        return beanDefinitions;
    }
}
